package org.bedracket.pgeg.datagen.levelgen;

import net.minecraft.core.Holder;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.worldgen.BootstapContext;
import net.minecraft.resources.ResourceKey;
import net.minecraft.world.level.levelgen.VerticalAnchor;
import net.minecraft.world.level.levelgen.feature.ConfiguredFeature;
import net.minecraft.world.level.levelgen.placement.*;
import org.bedracket.pgeg.util.Helpers;

import java.util.List;

public class ModPlacedFeatureProvider {

    public static final ResourceKey<PlacedFeature> ORE_AIR_INFUSED_STONE_PLACED =
            register("ore_air_infused_stone_placed");
    public static final ResourceKey<PlacedFeature> ORE_AQUA_INFUSED_STONE_PLACED =
            register("ore_aqua_infused_stone_placed");
    public static final ResourceKey<PlacedFeature> ORE_FIRE_INFUSED_STONE_PLACED =
            register("ore_fire_infused_stone_placed");
    public static final ResourceKey<PlacedFeature> ORE_EARTH_INFUSED_STONE_PLACED =
            register("ore_earth_infused_stone_placed");
    public static final ResourceKey<PlacedFeature> ORE_ENTROPY_INFUSED_STONE_PLACED =
            register("ore_entropy_infused_stone_placed");
    public static final ResourceKey<PlacedFeature> ORE_ORDER_INFUSED_STONE_PLACED =
            register("ore_order_infused_stone_placed");
    public static final ResourceKey<PlacedFeature> ORE_AIR_INFUSED_DEEPSLATE_PLACED =
            register("ore_air_infused_deepslate_placed");
    public static final ResourceKey<PlacedFeature> ORE_AQUA_INFUSED_DEEPSLATE_PLACED =
            register("ore_aqua_infused_deepslate_placed");
    public static final ResourceKey<PlacedFeature> ORE_FIRE_INFUSED_DEEPSLATE_PLACED =
            register("ore_fire_infused_deepslate_placed");
    public static final ResourceKey<PlacedFeature> ORE_EARTH_INFUSED_DEEPSLATE_PLACED =
            register("ore_earth_infused_deepslate_placed");
    public static final ResourceKey<PlacedFeature> ORE_ENTROPY_INFUSED_DEEPSLATE_PLACED =
            register("ore_entropy_infused_deepslate_placed");
    public static final ResourceKey<PlacedFeature> ORE_ORDER_INFUSED_DEEPSLATE_PLACED =
            register("ore_order_infused_deepslate_placed");
    public static final ResourceKey<PlacedFeature> BRIMSTONE_ORE_PLACED =
            register("brimstone_ore_placed");
    public static final ResourceKey<PlacedFeature> METEORITE_ORE_PLACED =
            register("meteorite_ore_placed");
    public static final ResourceKey<PlacedFeature> MITHRIL_ORE_PLACED =
            register("mithril_ore_placed");
    public static final ResourceKey<PlacedFeature> ORICHALCUM_ORE_PLACED =
            register("orichalcum_ore_placed");
    public static final ResourceKey<PlacedFeature> SATURNIUM_ORE_PLACED =
            register("saturnium_ore_placed");
    public static final ResourceKey<PlacedFeature> SILVER_ORE_PLACED =
            register("silver_ore_placed");

    public static final ResourceKey<PlacedFeature> DEEPSLATE_BRIMSTONE_ORE_PLACED =
            register("deepslate_brimstone_ore_placed");
    public static final ResourceKey<PlacedFeature> DEEPSLATE_METEORITE_ORE_PLACED =
            register("deepslate_meteorite_ore_placed");
    public static final ResourceKey<PlacedFeature> DEEPSLATE_MITHRIL_ORE_PLACED =
            register("deepslate_mithril_ore_placed");
    public static final ResourceKey<PlacedFeature> DEEPSLATE_ORICHALCUM_ORE_PLACED =
            register("deepslate_orichalcum_ore_placed");
    public static final ResourceKey<PlacedFeature> DEEPSLATE_SATURNIUM_ORE_PLACED =
            register("deepslate_saturnium_ore_placed");
    public static final ResourceKey<PlacedFeature> DEEPSLATE_SILVER_ORE_PLACED =
            register("deepslate_silver_ore_placed");


    public static void placedFeature(BootstapContext<PlacedFeature> context) {
        HolderGetter<ConfiguredFeature<?, ?>> holderGetter =
                context.lookup(Registries.CONFIGURED_FEATURE);
        Holder<ConfiguredFeature<?, ?>> ore_air_infused_stone_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_AIR_INFUSED_STONE);
        Holder<ConfiguredFeature<?, ?>> ore_fire_infused_stone_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_FIRE_INFUSED_STONE);
        Holder<ConfiguredFeature<?, ?>> ore_earth_infused_stone_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_EARTH_INFUSED_STONE);
        Holder<ConfiguredFeature<?, ?>> ore_entropy_infused_stone_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_ENTROPY_INFUSED_STONE);
        Holder<ConfiguredFeature<?, ?>> ore_order_infused_stone_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_ORDER_INFUSED_STONE);
        Holder<ConfiguredFeature<?, ?>> ore_aqua_infused_stone_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_AQUA_INFUSED_STONE);
        Holder<ConfiguredFeature<?, ?>> ore_air_infused_deepslate_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_AIR_INFUSED_DEEPSLATE);
        Holder<ConfiguredFeature<?, ?>> ore_fire_infused_deepslate_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_FIRE_INFUSED_DEEPSLATE);
        Holder<ConfiguredFeature<?, ?>> ore_earth_infused_deepslate_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_EARTH_INFUSED_DEEPSLATE);
        Holder<ConfiguredFeature<?, ?>> ore_entropy_infused_deepslate_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_ENTROPY_INFUSED_DEEPSLATE);
        Holder<ConfiguredFeature<?, ?>> ore_order_infused_deepslate_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_ORDER_INFUSED_DEEPSLATE);
        Holder<ConfiguredFeature<?, ?>> ore_aqua_infused_deepslate_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORE_AQUA_INFUSED_DEEPSLATE);
        Holder<ConfiguredFeature<?, ?>> brimstone_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.BRIMSTONE_ORE);
        Holder<ConfiguredFeature<?, ?>> meteorite_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.METEORITE_ORE);
        Holder<ConfiguredFeature<?, ?>> mithril_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.MITHRIL_ORE);
        Holder<ConfiguredFeature<?, ?>> orichalcum_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.ORICHALCUM_ORE);
        Holder<ConfiguredFeature<?, ?>> saturnium_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.SATURNIUM_ORE);
        Holder<ConfiguredFeature<?, ?>> silver_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.SILVER_ORE);
        Holder<ConfiguredFeature<?, ?>> deepslate_brimstone_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.DEEPSLATE_BRIMSTONE_ORE);
        Holder<ConfiguredFeature<?, ?>> deepslate_meteorite_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.DEEPSLATE_METEORITE_ORE);
        Holder<ConfiguredFeature<?, ?>> deepslate_mithril_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.DEEPSLATE_MITHRIL_ORE);
        Holder<ConfiguredFeature<?, ?>> deepslate_orichalcum_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.DEEPSLATE_ORICHALCUM_ORE);
        Holder<ConfiguredFeature<?, ?>> deepslate_saturnium_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.DEEPSLATE_SATURNIUM_ORE);
        Holder<ConfiguredFeature<?, ?>> deepslate_silver_ore_holder =
                holderGetter.getOrThrow(ModConfiguredFeatureProvider.DEEPSLATE_SILVER_ORE);
        context.register(ORE_AIR_INFUSED_STONE_PLACED,
                new PlacedFeature(ore_air_infused_stone_holder,
                commonOrePlacement(4,
                        HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                VerticalAnchor.absolute(15)))));
        context.register(ORE_FIRE_INFUSED_STONE_PLACED,
                new PlacedFeature(ore_fire_infused_stone_holder,
                        commonOrePlacement(4,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(ORE_EARTH_INFUSED_STONE_PLACED,
                new PlacedFeature(ore_earth_infused_stone_holder,
                        commonOrePlacement(4,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(ORE_ENTROPY_INFUSED_STONE_PLACED,
                new PlacedFeature(ore_entropy_infused_stone_holder,
                        commonOrePlacement(4,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(ORE_ORDER_INFUSED_STONE_PLACED,
                new PlacedFeature(ore_order_infused_stone_holder,
                        commonOrePlacement(4,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(ORE_AQUA_INFUSED_STONE_PLACED,
                new PlacedFeature(ore_aqua_infused_stone_holder,
                        commonOrePlacement(4,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(ORE_AIR_INFUSED_DEEPSLATE_PLACED,
                new PlacedFeature(ore_air_infused_deepslate_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(ORE_FIRE_INFUSED_DEEPSLATE_PLACED,
                new PlacedFeature(ore_fire_infused_deepslate_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.triangle(VerticalAnchor.aboveBottom(-32),
                                        VerticalAnchor.absolute(15)))));
        context.register(ORE_EARTH_INFUSED_DEEPSLATE_PLACED,
                new PlacedFeature(ore_earth_infused_deepslate_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.triangle(VerticalAnchor.aboveBottom(-32),
                                        VerticalAnchor.absolute(15)))));
        context.register(ORE_ENTROPY_INFUSED_DEEPSLATE_PLACED,
                new PlacedFeature(ore_entropy_infused_deepslate_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.triangle(VerticalAnchor.aboveBottom(-32),
                                        VerticalAnchor.absolute(15)))));
        context.register(ORE_ORDER_INFUSED_DEEPSLATE_PLACED,
                new PlacedFeature(ore_order_infused_deepslate_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.triangle(VerticalAnchor.aboveBottom(-32),
                                        VerticalAnchor.absolute(15)))));
        context.register(ORE_AQUA_INFUSED_DEEPSLATE_PLACED,
                new PlacedFeature(ore_aqua_infused_deepslate_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.triangle(VerticalAnchor.aboveBottom(-32),
                                        VerticalAnchor.absolute(15)))));
        context.register(BRIMSTONE_ORE_PLACED,
                new PlacedFeature(brimstone_ore_holder,
                        commonOrePlacement(4,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(METEORITE_ORE_PLACED,
                new PlacedFeature(meteorite_ore_holder,
                        commonOrePlacement(4,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(MITHRIL_ORE_PLACED,
                new PlacedFeature(mithril_ore_holder,
                        commonOrePlacement(4,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(ORICHALCUM_ORE_PLACED,
                new PlacedFeature(orichalcum_ore_holder,
                        commonOrePlacement(4,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(SATURNIUM_ORE_PLACED,
                new PlacedFeature(saturnium_ore_holder,
                        commonOrePlacement(4,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(SILVER_ORE_PLACED,
                new PlacedFeature(silver_ore_holder,
                        commonOrePlacement(4,
                                HeightRangePlacement.uniform(VerticalAnchor.bottom(),
                                        VerticalAnchor.absolute(15)))));
        context.register(DEEPSLATE_BRIMSTONE_ORE_PLACED,
                new PlacedFeature(deepslate_brimstone_ore_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.uniform(VerticalAnchor.aboveBottom(-32),
                                        VerticalAnchor.absolute(15)))));
        context.register(DEEPSLATE_METEORITE_ORE_PLACED,
                new PlacedFeature(deepslate_meteorite_ore_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.uniform(VerticalAnchor.aboveBottom(-32),
                                        VerticalAnchor.absolute(15)))));
        context.register(DEEPSLATE_MITHRIL_ORE_PLACED,
                new PlacedFeature(deepslate_mithril_ore_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.uniform(VerticalAnchor.aboveBottom(-32),
                                        VerticalAnchor.absolute(15)))));
        context.register(DEEPSLATE_ORICHALCUM_ORE_PLACED,
                new PlacedFeature(deepslate_orichalcum_ore_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.uniform(VerticalAnchor.aboveBottom(-32),
                                        VerticalAnchor.absolute(15)))));
        context.register(DEEPSLATE_SATURNIUM_ORE_PLACED,
                new PlacedFeature(deepslate_saturnium_ore_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.uniform(VerticalAnchor.aboveBottom(-32),
                                        VerticalAnchor.absolute(15)))));
        context.register(DEEPSLATE_SILVER_ORE_PLACED,
                new PlacedFeature(deepslate_silver_ore_holder,
                        commonOrePlacement(8,
                                HeightRangePlacement.uniform(VerticalAnchor.aboveBottom(-32),
                                        VerticalAnchor.absolute(15)))));
    }

    private static List<PlacementModifier> orePlacement(PlacementModifier p_195347_, PlacementModifier p_195348_) {
        return List.of(p_195347_, InSquarePlacement.spread(), p_195348_, BiomeFilter.biome());
    }

    private static List<PlacementModifier> commonOrePlacement(int pCount, PlacementModifier pHeightRange) {
        return orePlacement(CountPlacement.of(pCount), pHeightRange);
    }

    private static List<PlacementModifier> rareOrePlacement(int pChance, PlacementModifier pHeightRange) {
        return orePlacement(RarityFilter.onAverageOnceEvery(pChance), pHeightRange);
    }

    private static ResourceKey<PlacedFeature> register(String name) {
        return ResourceKey.create(Registries.PLACED_FEATURE, Helpers.identifier(name));
    }

}
